package com.push.alipush;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ServiceInfo;
import android.graphics.Color;
import android.os.Build;
import android.text.TextUtils;
import android.util.Log;

import com.alibaba.sdk.android.push.CloudPushService;
import com.alibaba.sdk.android.push.CommonCallback;
import com.alibaba.sdk.android.push.huawei.HuaWeiRegister;
import com.alibaba.sdk.android.push.noonesdk.PushInitConfig;
import com.alibaba.sdk.android.push.noonesdk.PushServiceFactory;
import com.alibaba.sdk.android.push.register.GcmRegister;
import com.alibaba.sdk.android.push.register.MeizuRegister;
import com.alibaba.sdk.android.push.register.MiPushRegister;
import com.alibaba.sdk.android.push.register.OppoRegister;
import com.alibaba.sdk.android.push.register.VivoRegister;

import java.util.HashMap;
import java.util.Map;

import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;
import androidx.core.graphics.drawable.IconCompat;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;

/**
 * AlipushFlutterPlugin
 */
public class AlipushFlutterPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware {
    private static final String CHANNEL_ID = "1";
    private MethodChannel channel;
    private Activity context;
    private final Map<String, Result> callbackMap;
    public static AlipushFlutterPlugin instance;
    private static final String TAG = "AliPushPlugin";
    private boolean enableLog = false;

    public AlipushFlutterPlugin() {
        this.callbackMap = new HashMap<>();
        instance = this;
    }

    @Override
    public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
        channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "com.jacky.util/alipush");
        channel.setMethodCallHandler(this);
    }

    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
        String method = call.method;
        switch (method) {
            case "setup":
                setup(call, result);
                break;
            case "setLogEnable":
                setLogEnable(call, result);
                break;
            case "setAlias":
                setAlias(call, result);
                break;
            case "deleteAlias":
                deleteAlias(call, result);
                break;
            case "setBadge":
                setBadge(call, result);
                break;
            case "setPushOnActive":
                setPushOnActive(call, result);
                break;
            case "setNotificationSoundFilePath":
                setNotificationSoundFilePath(call, result);
                break;
            case "showNotification":
                showNotification(call);
                result.success(null);
                break;
            default:
                result.notImplemented();
                break;
        }
    }

    @Override
    public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
        channel.setMethodCallHandler(null);
    }

    /**
     * 在这里初始化，不知道是否可以：根据ali文档，要求这部分初始化要运行在 application中的onCreate方法中
     */
    private void setup(MethodCall call, Result result) {
        if(context == null) return;

        Map<String, String> map = (Map<String, String>) call.arguments;
        String appKey = map.get("appKey");
        String appSecret = map.get("appSecret");
        if (appKey == null || appSecret == null) {
            PushServiceFactory.init(context);
        } else {
            PushInitConfig config =
                    new PushInitConfig.Builder().application(context.getApplication())
                    .appKey(appKey).appSecret(appSecret).build();
            PushServiceFactory.init(config);
        }
        createNotificationChannel();
        CloudPushService pushService = PushServiceFactory.getCloudPushService();
        pushService.setLogLevel(enableLog ? CloudPushService.LOG_DEBUG : CloudPushService.LOG_OFF);
        pushService.register(context, getCallback("setup", result));

        checkChannel();
        //初始化小米推送
        String xiaomiId = map.get("xiaomiId");
        String xiaomiKey = map.get("xiaomiKey");
        if(TextUtils.isEmpty(xiaomiId) || TextUtils.isEmpty(xiaomiKey)) {
            Log.w(TAG, "xiaomi push register fail.Please check xiaomiId or xiaomiKey.");
        } else {
            boolean r = MiPushRegister.register(context, xiaomiId, xiaomiKey);
            log(TAG, "xiaomi push register success: " + r);
        }

        //初始化oppo推送
        String oppoKey = map.get("oppoKey");
        String oppoSecret = map.get("oppoSecret");
        if(TextUtils.isEmpty(oppoKey) || TextUtils.isEmpty(oppoSecret)) {
            Log.w(TAG, "oppo push register fail.Please check oppoKey or oppoSecret.");
        } else {
            boolean r = OppoRegister.register(context, oppoKey, oppoSecret);
            log(TAG, "oppo push register success: " + r);
        }

        //初始化魅族推送
        String meizuAppId = map.get("meizuAppId");
        String meizuAppKey = map.get("meizuAppKey");
        if(TextUtils.isEmpty(meizuAppId) || TextUtils.isEmpty(meizuAppKey)) {
            Log.w(TAG, "meizu push register fail.Please check meizuAppId or meizuAppKey.");
        } else {
            try {
                Class.forName("com.alibaba.sdk.android.push.register.MeizuRegister");
                boolean r = MeizuRegister.register(context, meizuAppId, meizuAppKey);
                log(TAG, "meizu push register success: " + r);
            } catch (ClassNotFoundException e) {
                Log.w(TAG, "meizu push register fail...");
            }
        }

        //初始化google推送
        String gcmSendId = map.get("gcmSendId");
        String gcmAppId = map.get("gcmAppId");
        String gcmProjectId = map.get("gcmProjectId");
        String gcmApikey = map.get("gcmApikey");
        if(TextUtils.isEmpty(gcmSendId) || TextUtils.isEmpty(gcmAppId)) {
            Log.w(TAG, "google push register fail.Please check gcmSendId or gcmAppId.");
        } else {
            try {
                Class.forName("com.alibaba.sdk.android.push.register.GcmRegister");
                boolean r = GcmRegister.register(context, gcmSendId, gcmAppId, gcmProjectId,gcmApikey);
                log(TAG, "google push register success: " + r);
            } catch (ClassNotFoundException e) {
                Log.w(TAG, "google push register fail...");
            }
        }
    }

    private void checkChannel() {
        try {
            Class.forName("com.alibaba.sdk.android.push.huawei.HuaWeiRegister");
            boolean r = HuaWeiRegister.register(context.getApplication());
            log(TAG, "Huawei push register success: " + r);
        } catch (ClassNotFoundException e) {
            Log.w(TAG, "Huawei push register fail...");
        }
        try {
            Class.forName("com.alibaba.sdk.android.push.register.VivoRegister");
            boolean r= VivoRegister.register(context);
            log(TAG, "vivo push register success: " + r);
        } catch (ClassNotFoundException e) {
            Log.w(TAG, "Vivo push register fail...");
        }
    }

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            // 用户可以看到的通知渠道的名字.
            CharSequence name = context.getString(R.string.notification_name);
            // 用户可以看到的通知渠道的描述
            String description = context.getString(R.string.notification_description);
            int importance = NotificationManager.IMPORTANCE_HIGH;
            NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, name, importance);
            // 配置通知渠道的属性
            mChannel.setDescription(description);
            // 设置通知出现时的闪灯（如果 android 设备支持的话）
            mChannel.enableLights(true);
            mChannel.setLightColor(Color.RED);
            // 设置通知出现时的震动（如果 android 设备支持的话）
            mChannel.enableVibration(true);
            // 是否在桌面显示角标
            mChannel.setShowBadge(true);
            mChannel.setVibrationPattern(new long[]{100, 200, 300, 400, 500, 400, 300, 200, 400});
            //最后在notificationmanager中创建该通知渠道
            mNotificationManager.createNotificationChannel(mChannel);
        }
    }

    @SuppressLint("LaunchActivityFromNotification")
    private void showNotification(MethodCall call) {
        String title = (String) call.argument("title");
        String content = (String) call.argument("content");
        String params = (String) call.argument("params");
        String icon = (String) call.argument("icon");
        if(icon == null || icon.isEmpty()) {
            icon = "ic_launcher";
        }
        NotificationCompat.Builder notification = new NotificationCompat.Builder(context, CHANNEL_ID)
                .setContentTitle(title)
                .setContentText(content)
                .setAutoCancel(true)
                .setSmallIcon(context.getResources().getIdentifier(icon, "mipmap", context.getPackageName()));
        if(params != null && !params.isEmpty()) {
            Intent intent = new Intent();
            intent.setAction("com.push.CLICK_ACTION");
            intent.putExtra("params", params);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
            notification.setContentIntent(pendingIntent);
        }
        NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        int id = (int) System.currentTimeMillis();
        mNotificationManager.notify(id, notification.build());
    }

    /**
     * 是否开启日志输出,默认关闭
     */
    private void setLogEnable(MethodCall call, Result result) {
        Boolean enable = call.argument("enable");
        enableLog = enable != null && enable;
        int log = enableLog ? CloudPushService.LOG_DEBUG : CloudPushService.LOG_OFF;
        PushServiceFactory.getCloudPushService().setLogLevel(log);
        result.success(enable);
    }

    /**
     * 为设备添加别名
     * 单个设备最多添加128个别名，同一个别名最多可被添加到128个设备
     * 别名支持的最大长度为128字节
     */
    private void setAlias(MethodCall call, Result result) {
        String alias = (String) call.arguments;
        PushServiceFactory.getCloudPushService().addAlias(alias, getCallback("setAlias", result));
    }

    /**
     * 支持删除指定别名和删除全部别名
     */
    private void deleteAlias(MethodCall call, Result result) {
        //alias = null or alias.length = 0 时，删除设备全部别名。
        String alias = (String) call.arguments;
        PushServiceFactory.getCloudPushService().removeAlias(alias, getCallback("deleteAlias", result));
    }

    /**
     * 设置应用 Badge（小红点）,iOS自动管理一般不需要设置， Android这边没有对应处理
     */
    private void setBadge(MethodCall call, Result result) {
        Integer badge = call.argument("badge");
        result.success(true);
    }

    /**
     * ios:当应用处于前台时收到推送，是否显示推送弹窗，默认否，Android没有处理
     */
    private void setPushOnActive(MethodCall call, Result result) {
        Boolean active = call.argument("active");
        result.success(true);
    }

    /**
     * 设置推送通知声音文件路径。注意android 8.0以上需要使用NotificationChannel配置声音
     * 若不调用本接口，默认获取资源id为R.raw.alicloud_notification_sound的资源文件
     * 若没有获取到指定声音文件，取设备设置的消息声音。
     */
    private void setNotificationSoundFilePath(MethodCall call, Result result) {
        HashMap<String, Object> map = call.arguments();
        String filePath = (String) map.get("filePath");
        Object form = map.get("form");

        if("1".equals(form)) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                filePath = "file:///android_assets/flutter_assets/" + filePath;
            } else {
                Log.w(TAG, "Build Version < 26,asset path not support...");
                return;
            }
        } else if("2".equals(form)) {
            filePath = "android.resource://" + context.getPackageName() + "/raw/" + filePath;
        }

        log(TAG, "Notification Sound Path : " + filePath);
        PushServiceFactory.getCloudPushService().setNotificationSoundFilePath(filePath);
        result.success(true);
    }

    public CommonCallback getCallback(final String tag, Result result) {
        callbackMap.put(tag, result);
        return new CommonCallback() {
            @Override
            public void onSuccess(String response) {
                log(TAG, "method " + tag + ", response" + response);
                resultSuccess(tag, response);
            }

            @Override
            public void onFailed(String errorCode, String errorMessage) {
                log(TAG, "method " + tag + ", errorCode=" + errorCode + ", errorMessage=" + errorMessage);
                resultError(tag, errorCode, errorMessage);
            }
        };
    }

    public void resultSuccess(String tag, Object message) {
        Result res = callbackMap.get(tag);
        if (res != null) {
            res.success(message);
            callbackMap.remove(tag);
        }
    }

    public void resultError(String tag, String errorCode, String errorMessage) {
        Result res = callbackMap.get(tag);
        if (res != null) {
            res.error(errorCode, errorMessage, errorMessage);
            callbackMap.remove(tag);
        }
    }

    /**
     * 主线程再返回数据
     */
    public void runMainThread(final Object map, final Result result, final String method) {
        Log.d(TAG, "runMainThread:" + "map = " + map + ",method =" + method);
        context.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (result == null && method != null) {
                    channel.invokeMethod(method, map);
                } else if (result != null) {
                    result.success(map);
                } else {
                    Log.d(TAG, "runMainThread result and method is null");
                }
            }
        });
    }

    public void log(String tag, String message) {
        if (enableLog) {
            Log.i(tag, message);
        }
    }

    @Override
    public void onAttachedToActivity(ActivityPluginBinding binding) {
        context = binding.getActivity();
    }

    @Override
    public void onDetachedFromActivityForConfigChanges() {

    }

    @Override
    public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {
        onAttachedToActivity(binding);
    }

    @Override
    public void onDetachedFromActivity() {
        context = null;
    }
}
